import type * as RspackChain from 'rspack-chain'
import { resolve } from 'path'
import { rspack } from '@rspack/core'
import {
	getPkgMajorVersion,
	loadConfig,
	logWarning,
	judgeFramework,
	getBuildConfig,
	getDefineEnv,
	loadModuleFromRspack
} from 'ssr-common-utils'
import { nodeExternals } from './externals'
import type { Plugin as PostCssPlugin } from 'postcss'

const [antdVersion] = [getPkgMajorVersion('antd'), getPkgMajorVersion('vant')]
if (antdVersion === 5) {
	logWarning('Check antd@5.x has been installed, antd@4.x is more recommend in ssr environment')
}

const addCommonChain = (chain: RspackChain, isServer: boolean) => {
	const { cwd, whiteList, define, defaultBrowserTarget, isDev, css } = loadConfig()

	if (process.env.NOMINIFY) {
		chain.optimization.minimize(false)
	}
	chain.devtool(((isServer ? process.env.SERVER_SOURCEMAP : process.env.CLIENT_SOURCEMAP) as any) ?? false)
	if (!isServer) {
		chain.externals(
			nodeExternals({
				isServer
			})
		)
	} else {
		const modulesDir = [resolve(cwd, './node_modules')]
		chain.externals(
			nodeExternals({
				isServer,
				whitelist: whiteList,
				// externals Dir contains example/xxx/node_modules ssr/node_modules
				modulesDir
			})
		)
	}

	chain.module.rule('mjs').test(/\.mjs/).type('javascript/auto').end()
	chain.module
		.rule('js')
		.test(/\.(jsx?|tsx?)$/)
		.use('swc-loader')
		.loader('builtin:swc-loader')
		.options({
			jsc: {
				parser: {
					syntax: 'typescript',
					tsx: true
				},
				...(judgeFramework() === 'ssr-plugin-react'
					? {
							transform: {
								react: {
									runtime: 'automatic',
									development: isDev,
									refresh: isDev && !isServer
								}
							}
						}
					: {})
			},
			env: { targets: defaultBrowserTarget }
		})
		.end()
	chain.module
		.rule('images')
		.test(/\.(jpe?g|png|svg|gif)(\?[a-z0-9=.]+)?$/)
		.type('asset/resource')
		.end()
	chain.module
		.rule('fonts')
		.test(/\.(eot|woff|woff2|ttf)(\?.*)?$/)
		.type('asset/resource')
		.end()

	if (isServer) {
		chain.module.generator.set('asset/resource', {
			emit: false
		})
		chain.module.generator.set('asset', {
			emit: false
		})
	}

	const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
	const generateAnalysis = Boolean(process.env.GENERATE_ANALYSIS)
	chain.experiments({
		css: true
	})
	chain.module.parser.set('css/auto', {
		namedExports: false
	})
	const postCssPlugins = css?.().loaderOptions?.postcss?.plugins ?? [] // 用户自定义 postcss 插件
	const userPostcssOptions = css?.().loaderOptions?.postcss?.options
	const postcssOptions =
		typeof userPostcssOptions === 'function'
			? userPostcssOptions
			: Object.assign(
					{
						plugins: ([] as PostCssPlugin[]).concat(postCssPlugins)
					},
					userPostcssOptions ?? {}
				)
	const lessChain = chain.module
		.rule('less')
		.test(/\.less/)
		.type('css/auto')

	if (css?.().loaderOptions?.postcss) {
		chain.module
			.rule('css-postcss')
			.test(/\.css/)
			.type('css/auto')
			.use('postcss-loader')
			.loader(loadModuleFromRspack('postcss-loader'))
			.options({
				postcssOptions: postcssOptions
			})
			.end()

		lessChain
			.use('post-css')
			.loader(loadModuleFromRspack('postcss-loader'))
			.options({
				postcssOptions: postcssOptions
			})
			.end()
	}

	lessChain
		.use('less-loader')
		.loader(loadModuleFromRspack('less-loader'))
		.options({
			lessOptions: Object.assign(
				{
					lessOptions: {
						javascriptEnabled: true
					}
				},
				css?.().loaderOptions?.less
			)
		})
		.end()

	chain.plugin('minify-css').use(rspack.CssExtractRspackPlugin, [getBuildConfig().cssBuildConfig[0]])

	chain.plugin('ssrDefine').use(rspack.DefinePlugin, [
		{
			...getDefineEnv(),
			...process.env,
			__isBrowser__: !isServer,
			__VUE_OPTIONS_API__: true,
			__VUE_PROD_DEVTOOLS__: false,
			...(isServer ? define?.server : define?.client),
			...define?.base
		}
	])

	if (!isServer) {
		chain.when(generateAnalysis, (chain) => {
			chain.plugin('analyze').use(BundleAnalyzerPlugin)
		})
	}
}

export { addCommonChain }
